# -*- coding: utf-8 -*-
#
# The Philatelist program is a fork of the OpenNumismat program
# Copyright (c) 2011 - 2024 Vitaly Ignatov (OpenNumismat) <opennumismat@gmail.com>
# Copyright (c) 2021 - 2024 Victor Nabatov (Philatelist) <nabatov.victor@gmail.com>
#

from dataclasses import dataclass
from PySide6.QtCore import QObject, QT_TRANSLATE_NOOP
from PySide6.QtSql import QSqlDatabase, QSqlQuery
from PySide6.QtWidgets import QApplication


class FieldTypes():

    String = 1
    ShortString = 2
    Number = 3
    Text = 4
    Money = 5
    Date = 6
    BigInt = 7
    Image = 8
    Char = 9
    Status = 10
    DateTime = 11
    PreviewImage = 13

    Mask = 0xFF
    Checkable = 0x100
    Disabled = 0x200

    ImageTypes = (Image, PreviewImage)

    @staticmethod
    def toSql(type_):
        if type_ == FieldTypes.String:
            sql_type = 'CHAR'
        elif type_ == FieldTypes.ShortString:
            sql_type = 'CHAR'
        elif type_ == FieldTypes.Number:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.Text:
            sql_type = 'TEXT'
        elif type_ == FieldTypes.Money:
            sql_type = 'NUMERIC'
        elif type_ == FieldTypes.Date:
            sql_type = 'CHAR'
        elif type_ == FieldTypes.BigInt:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.Image:
            sql_type = 'INTEGER'
        elif type_ == FieldTypes.Char:
            sql_type = 'CHAR'
        elif type_ == FieldTypes.Status:
            sql_type = 'CHAR'
        elif type_ == FieldTypes.DateTime:
            sql_type = 'CHAR'
        elif type_ == FieldTypes.PreviewImage:
            sql_type = 'INTEGER'
        else:
            raise TypeError

        return sql_type


class Status(dict):

    def __init__(self):
        self['demo'] = QT_TRANSLATE_NOOP("Status", "Demo")
        self['owned'] = QT_TRANSLATE_NOOP("Status", "Owned")
        self['wish'] = QT_TRANSLATE_NOOP("Status", "Wish")
        self['duplicate'] = QT_TRANSLATE_NOOP("Status", "Duplicate")    # In collection, but not for sale or exchange yet
        self['ordered'] = QT_TRANSLATE_NOOP("Status", "Ordered")        # Paid for, but not in the collection yet
        self['sale'] = QT_TRANSLATE_NOOP("Status", "Sale")              # Put up for sale / auction
        self['sold'] = QT_TRANSLATE_NOOP("Status", "Sold")
        self['exchange'] = QT_TRANSLATE_NOOP("Status", "Exchange")      # Will be or can be exchanged
        self['variety'] = QT_TRANSLATE_NOOP("Status", "Variety")
        self['rarity'] = QT_TRANSLATE_NOOP("Status", "Rarity")
        self.orders = {}
        for i, key in enumerate(self.keys()):
            self.orders[key] = i + 1

    def init(self, settings):
        for status in self.keys():
            self[status] = settings.Default[status + '_status_title']

    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)

        except KeyError:
            return ''

    def reverse(self, title):
        for key, value in self.items():
            if value == title:
                return key

        return ''

    def order(self, key):
        try:
            return self.orders[key]

        except KeyError:
            return 0

    def compare(self, left, right):
        return self.order(left) - self.order(right)


# TODO: Move Statuses to Collection
Statuses = Status()

ImagesFields = (
    'stamp_image',
    'reverse_image',
    'variety_image',
    'photo1',
    'photo2',
    'photo3',
    'photo4'
)
TraitsImagesFields = (
    'grid_image',
    'honeycomb_image',
    'raster_image',
    'watermark_image'
)
TraitsFields = (
    'grid',
    'honeycomb',
    'raster',
    'watermark'
)
TitleTemplateFields = (
    'denomination',
    'region',
    'country',
    'year',
    'series',
    'theme',
    'type',
    'material',
    'watermark'
)
TreeFields = (
    'region',
    'country',
    'title',
    'year',
    'type',
    'series',
    'theme',
    'status',
    'format',
    'cancellation',
    'printing',
    'perforation',
    'perforation_size',
    'material',
    'material_type',
    'condition',
    'grade',
    'seller',
    'pay_place',
    'buyer',
    'sale_place'
)
StatisticsFields = (
    'region',
    'country',
    'year',
    'type',
    'series',
    'theme',
    'status',
    'printing',
    'perforation'
    'material',
    'material_type',
    'cancellation',
    'watermark',
    'format',
    'condition',
    'grade',
    'designer',
    'expert',
    'seller',
    'pay_place',
    'buyer',
    'sale_place'
)


@dataclass(slots=True)
class CollectionField():

    id: int
    name: str
    title: str
    type: int
    enabled: bool


class CollectionFieldsBase(QObject):

    def __init__(self, parent=None):

        from Philatelist.Collection.CollectionFields import FieldTypes as Type

        super().__init__(parent)
        fields = [
            ('id', "ID", FieldTypes.BigInt),
            ("region", QApplication.translate('CollectionFieldsBase', "Region"), FieldTypes.ShortString),
            ("country", QApplication.translate('CollectionFieldsBase', "Country"), FieldTypes.ShortString),
            ('title', QApplication.translate('CollectionFieldsBase', "Title"), FieldTypes.String),
            ('denomination', QApplication.translate('CollectionFieldsBase', "Denomination"), FieldTypes.ShortString),
            ('year', QApplication.translate('CollectionFieldsBase', "Year"), FieldTypes.Number),
            ('stamp_year', QApplication.translate('CollectionFieldsBase', "Year on stamp"), FieldTypes.Number),
            ('theme', QApplication.translate('CollectionFieldsBase', "Theme"), FieldTypes.String),
            ('series', QApplication.translate('CollectionFieldsBase', "Series"), FieldTypes.String),
            ('type', QApplication.translate('CollectionFieldsBase', "Stamp type"), FieldTypes.ShortString),
            ('issue_date', QApplication.translate('CollectionFieldsBase', "Date of issue"), FieldTypes.Date),
            ('emission_period', QApplication.translate('CollectionFieldsBase', "Emission period"), FieldTypes.String),
            ('withdrawal', QApplication.translate('CollectionFieldsBase', "Date of withdrawal"), FieldTypes.ShortString),
            ('circulation', QApplication.translate('CollectionFieldsBase', "Circulation"), FieldTypes.BigInt),
            ('quantity', QApplication.translate('CollectionFieldsBase', "Quantity"), FieldTypes.Number),
            ('material', QApplication.translate('CollectionFieldsBase', "Material"), FieldTypes.ShortString),
            ('material_type', QApplication.translate('CollectionFieldsBase', "Material type"), FieldTypes.ShortString),
            ('thickness', QApplication.translate('CollectionFieldsBase', "Thickness"), FieldTypes.ShortString),
            ('printing', QApplication.translate('CollectionFieldsBase', "Printing"), FieldTypes.ShortString),
            ('perforation', QApplication.translate('CollectionFieldsBase', "Perforation"), FieldTypes.ShortString),
            ('perforation_size', QApplication.translate('CollectionFieldsBase', "Perforation size"), FieldTypes.Char),
            ('full_size', QApplication.translate('CollectionFieldsBase', "Full size"), FieldTypes.Char),
            ('picture_size', QApplication.translate('CollectionFieldsBase', "Picture size"), FieldTypes.Char),
            ('status', QApplication.translate('CollectionFieldsBase', "Status"), FieldTypes.Status),
            ('format', QApplication.translate('CollectionFieldsBase', "Format"), FieldTypes.ShortString),
            ('cancellation', QApplication.translate('CollectionFieldsBase', "Cancellation"), FieldTypes.ShortString),
            ('condition', QApplication.translate('CollectionFieldsBase', "Condition"), FieldTypes.ShortString),
            ('grade', QApplication.translate('CollectionFieldsBase', "Grade"), FieldTypes.String),
            ('certificate', QApplication.translate('CollectionFieldsBase', "Certificate of expertise"), FieldTypes.String),
            ('expertise_date', QApplication.translate('CollectionFieldsBase', "Date of expert assessment"), FieldTypes.Date),
            ('expert', QApplication.translate('CollectionFieldsBase', "Expert"), FieldTypes.ShortString),
            ('features', QApplication.translate('CollectionFieldsBase', "Features"), FieldTypes.Text),
            ('stamp_design', QApplication.translate('CollectionFieldsBase', "Design"), FieldTypes.Text),
            ('designer', QApplication.translate('CollectionFieldsBase', "Designer"), FieldTypes.ShortString),
            ('engraver', QApplication.translate('CollectionFieldsBase', "Engraver"), FieldTypes.ShortString),
            ('stamp_color1', QApplication.translate('CollectionFieldsBase', "Color1"), FieldTypes.String),
            ('stamp_color2', QApplication.translate('CollectionFieldsBase', "Color2"), FieldTypes.String),
            ('stamp_reverse', QApplication.translate('CollectionFieldsBase', "Glue features"), FieldTypes.Text),
            ('glue', QApplication.translate('CollectionFieldsBase', "Glue type"), FieldTypes.ShortString),
            ('glue_color', QApplication.translate('CollectionFieldsBase', "Glue color"), FieldTypes.ShortString),
            ('watermark', QApplication.translate('CollectionFieldsBase', "Watermark type"), FieldTypes.ShortString),
            ('raster', QApplication.translate('CollectionFieldsBase', "Raster type"), FieldTypes.ShortString),
            ('grid', QApplication.translate('CollectionFieldsBase', "Grid type"), FieldTypes.ShortString),
            ('honeycomb', QApplication.translate('CollectionFieldsBase', "Honeycomb type"), FieldTypes.ShortString),
            ('variety', QApplication.translate('CollectionFieldsBase', "Variety type"), FieldTypes.ShortString),
            ('variety_desc', QApplication.translate('CollectionFieldsBase', "Variety description"), FieldTypes.Text),
            ('url', QApplication.translate('CollectionFieldsBase', "URL"), FieldTypes.String),
            ('catalognum1', QApplication.translate('CollectionFieldsBase', "Standard-Collection"), FieldTypes.Char),
            ('catalognum2', QApplication.translate('CollectionFieldsBase', "Michel"), FieldTypes.Char),
            ('catalognum3', QApplication.translate('CollectionFieldsBase', "CFA/Solovjev"), FieldTypes.Char),
            ('catalognum4', QApplication.translate('CollectionFieldsBase', "Colnect.com"), FieldTypes.Char),
            ('price1', QApplication.translate('CollectionFieldsBase', "** MNH"), FieldTypes.Money),
            ('price2', QApplication.translate('CollectionFieldsBase', "* Mounted"), FieldTypes.Money),
            ('price3', QApplication.translate('CollectionFieldsBase', "(*) NG"), FieldTypes.Money),
            ('price4', "☉ " + QApplication.translate('CollectionFieldsBase', "Special"), FieldTypes.Money),
            ('price5', "☉ " + QApplication.translate('CollectionFieldsBase', "U"), FieldTypes.Money),
            ('price6', "☉ " + QApplication.translate('CollectionFieldsBase', "CTO"), FieldTypes.Money),
            ('currency', QApplication.translate('CollectionFieldsBase', "Currency"), FieldTypes.ShortString),
            ('pay_date', QApplication.translate('CollectionFieldsBase', "Purchase date"), FieldTypes.Date),
            ('pay_price', QApplication.translate('CollectionFieldsBase', "Purchase price"), FieldTypes.Money),
            ('total_pay_price', QApplication.translate('CollectionFieldsBase', "Paid"), FieldTypes.Money),
            ('seller', QApplication.translate('CollectionFieldsBase', "Seller"), FieldTypes.ShortString),
            ('pay_place', QApplication.translate('CollectionFieldsBase', "Purchase place"), FieldTypes.String),
            ('buying_invoice', QApplication.translate('CollectionFieldsBase', "Purchase invoice"), Type.String),
            ('pay_info', QApplication.translate('CollectionFieldsBase', "Additional purchase infomation"), FieldTypes.Text),
            ('sale_date', QApplication.translate('CollectionFieldsBase', "Sale date"), FieldTypes.Date),
            ('sale_price', QApplication.translate('CollectionFieldsBase', "Sale price"), FieldTypes.Money),
            ('total_sale_price', QApplication.translate('CollectionFieldsBase', "Revenue"), FieldTypes.Money),
            ('buyer', QApplication.translate('CollectionFieldsBase', "Buyer"), FieldTypes.ShortString),
            ('sale_place', QApplication.translate('CollectionFieldsBase', "Sale place"), FieldTypes.String),
            ('sale_invoice', QApplication.translate('CollectionFieldsBase', "Sale invoice"), Type.String),
            ('sale_info', QApplication.translate('CollectionFieldsBase', "Additional sale infomation"), FieldTypes.Text),
            ('image', QApplication.translate('CollectionFieldsBase', "Image"), FieldTypes.PreviewImage),
            ('stamp_image', QApplication.translate('CollectionFieldsBase', "Stamp image"), FieldTypes.Image),
            ('reverse_image', QApplication.translate('CollectionFieldsBase', "Glue image"), FieldTypes.Image),
            ('watermark_image', QApplication.translate('CollectionFieldsBase', "Watermark image"), FieldTypes.Image),
            ('raster_image', QApplication.translate('CollectionFieldsBase', "Raster image"), FieldTypes.Image),
            ('grid_image', QApplication.translate('CollectionFieldsBase', "Grid image"), FieldTypes.Image),
            ('honeycomb_image', QApplication.translate('CollectionFieldsBase', "Honeycomb image"), FieldTypes.Image),
            ('variety_image', QApplication.translate('CollectionFieldsBase', "Variety image"), FieldTypes.Image),
            ('photo1', QApplication.translate('CollectionFieldsBase', "Photo 1"), FieldTypes.Image),
            ('photo1_title', QApplication.translate('CollectionFieldsBase', "Photo 1 title"), FieldTypes.ShortString),
            ('photo2', QApplication.translate('CollectionFieldsBase', "Photo 2"), FieldTypes.Image),
            ('photo2_title', QApplication.translate('CollectionFieldsBase', "Photo 2 title"), FieldTypes.ShortString),
            ('photo3', QApplication.translate('CollectionFieldsBase', "Photo 3"), FieldTypes.Image),
            ('photo3_title', QApplication.translate('CollectionFieldsBase', "Photo 3 title"), FieldTypes.ShortString),
            ('photo4', QApplication.translate('CollectionFieldsBase', "Photo 4"), FieldTypes.Image),
            ('photo4_title', QApplication.translate('CollectionFieldsBase', "Photo 4 title"), FieldTypes.ShortString),
            ('notes', QApplication.translate('CollectionFieldsBase', "Notes"), FieldTypes.Text),
            ('rating', QApplication.translate('CollectionFieldsBase', "Rating"), FieldTypes.ShortString),
            ('create_date', QApplication.translate('CollectionFieldsBase', "Created at"), FieldTypes.DateTime),
            ('update_date', QApplication.translate('CollectionFieldsBase', "Updated at"), FieldTypes.DateTime),
            ('sort_id', QApplication.translate('CollectionFieldsBase', "Position"), FieldTypes.BigInt),
        ]

        self.fields = []
        for id_, field in enumerate(fields):
            self.fields.append(
                    CollectionField(id_, field[0], field[1], field[2], False)
            )
            setattr(self, self.fields[id_].name, self.fields[id_])

        self.systemFields = (
            self.id, self.create_date, self.update_date, self.image, self.sort_id
        )
        self.userFields = list(self.fields)
        for item in (self.id, self.create_date, self.update_date, self.sort_id):
            self.userFields.remove(item)

    def field(self, id_):
        return self.fields[id_]

    def __iter__(self):
        self.index = 0
        return self

    def __next__(self):
        if self.index == len(self.fields):
            raise StopIteration

        self.index = self.index + 1
        return self.fields[self.index - 1]


class CollectionFields(CollectionFieldsBase):

    def __init__(self, db, parent=None):
        super().__init__(parent)
        self.db = db
        if 'fields' not in self.db.tables():
            self.create(self.db)

        query = QSqlQuery(self.db)
        query.prepare("SELECT * FROM fields")
        query.exec_()
        self.userFields = []
        self.disabledFields = []
        while query.next():
            record = query.record()
            fieldId = record.value('id')
            field = self.field(fieldId)
            field.title = record.value('title')
            field.enabled = bool(record.value('enabled'))
            if field.enabled:
                self.userFields.append(field)
            else:
                self.disabledFields.append(field)

    def getCustomTitle(self, name):
        return self.__getattribute__(name).title

    def save(self):
        self.db.transaction()
        for field in self.fields:
            query = QSqlQuery(self.db)
            query.prepare("UPDATE fields SET title=?, enabled=? WHERE id=?")
            query.addBindValue(field.title)
            query.addBindValue(int(field.enabled))
            query.addBindValue(field.id)
            query.exec_()

        self.db.commit()

    @staticmethod
    def create(db=QSqlDatabase()):
        db.transaction()

        sql = """CREATE TABLE fields (
            id INTEGER NOT NULL PRIMARY KEY,
            title CHAR,
            enabled INTEGER
        )"""
        QSqlQuery(sql, db)

        fields = CollectionFieldsBase()
        for field in fields:
            query = QSqlQuery(db)
            query.prepare("""INSERT INTO fields (id, title, enabled) VALUES (?, ?, ?)""")
            query.addBindValue(field.id)
            query.addBindValue(field.title)
            enabled = field in fields.userFields
            query.addBindValue(int(enabled))
            query.exec_()

        db.commit()
